package com.sky.rabc.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sky.rabc.common.RedissonCommon;
import com.sky.rabc.dto.AddNewBackUserDTO;
import com.sky.rabc.dto.BackUserLoginDTO;
import com.sky.rabc.dto.UpdateBackUserDTO;
import com.sky.rabc.entity.BackUser;
import com.sky.rabc.enums.ServiceCode;
import com.sky.rabc.exception.ServiceException;
import com.sky.rabc.mapper.BackRoleMapper;
import com.sky.rabc.mapper.BackUserAndRoleMapper;
import com.sky.rabc.mapper.BackUserMapper;
import com.sky.rabc.po.LoginInfoPO;
import com.sky.rabc.service.BackUserService;
import com.sky.rabc.utils.AesCommon;
import com.sky.rabc.vo.LoginBackPermissionVO;
import com.sky.rabc.vo.LoginInfoResultVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @author 刘泓君
 * @className BackUserServiceImpl
 * @description 后台用户服务功能
 * @date 2024/6/22
 */
@Service
public class BackUserServiceImpl implements BackUserService {
    @Value("${rabc.aes.key}")
    private String aesKey;
    @Value("${rabc.aes.iv}")
    private String aesIv;
    private final BackRoleMapper backRoleMapper;
    private final BackUserMapper backUserMapper;
    private final ObjectMapper objectMapper;
    private final RedissonCommon redissonCommon;
    private final BackUserAndRoleMapper backUserAndRoleMapper;

    public BackUserServiceImpl(BackRoleMapper backRoleMapper, BackUserMapper backUserMapper, ObjectMapper objectMapper, RedissonCommon redissonCommon, BackUserAndRoleMapper backUserAndRoleMapper) {
        this.backRoleMapper = backRoleMapper;
        this.backUserMapper = backUserMapper;
        this.objectMapper = objectMapper;
        this.redissonCommon = redissonCommon;
        this.backUserAndRoleMapper = backUserAndRoleMapper;
    }

    @Override
    public LoginInfoResultVO login(BackUserLoginDTO backUserLoginDTO) {
        LoginInfoPO longinInfo = backUserMapper.getLonginInfo(backUserLoginDTO.getAccount());
        String password;
        try {
            //加密密码
            password = AesCommon.encryptToStr(backUserLoginDTO.getPassword(), aesKey, aesIv, AesCommon.AES_CBC_PKCS5);
            backUserLoginDTO.setPassword(password);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        // 判断用户是否存在
        validateBackUser(longinInfo, backUserLoginDTO);
        // 生成token
        String token = creteToken(longinInfo.getId(), longinInfo.getRoleIds());
        // 存入redis中，过期时间5分钟
        redissonCommon.setValue("token:userId:" + longinInfo.getId(), token, 300000L);
        //根据roleId[],在redis中获取权限list
        List<LoginBackPermissionVO> permissionListItemByRedis = getPermissionListByRedis(longinInfo.getRoleIds());
        // 组装登录返回信息
        LoginInfoResultVO loginInfoResultVO = new LoginInfoResultVO();
        loginInfoResultVO.setId(longinInfo.getId());
        loginInfoResultVO.setAccount(longinInfo.getAccount());
        loginInfoResultVO.setName(longinInfo.getName());
        loginInfoResultVO.setToken(token);
        loginInfoResultVO.setLoginBackPermissionList(permissionListItemByRedis);
        return loginInfoResultVO;
    }

    @Override
    public void delUserById(Long id) {
        //判断id数据是否存在
        Long countedUser = backUserMapper.countUserById(id);
        if (countedUser <= 0) {
            throw new ServiceException(ServiceCode.ERROR_DELETE, "删除失败，数据不存在");
        }
        //查询关联表中是否存在数据
        int counted = backUserAndRoleMapper.countUserAndRoleByRoleId(id);
        if (counted > 1) {
            backUserAndRoleMapper.del(id);
        }
        int delResult = backUserMapper.delUserById(id);
        if (delResult != 1) {
            throw new ServiceException(ServiceCode.ERROR_DELETE, "删除失败");
        }
    }

    @Override
    public void updateUserInfoById(UpdateBackUserDTO updateBackUserDTO) {
        //数据是否存在
        Long countResult = backUserMapper.countUserById(updateBackUserDTO.getId());
        if (countResult <= 0) {
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND, "数据不存在");
        }
        int updateResult = backUserMapper.update(updateBackUserDTO);
        if (updateResult != 1) {
            throw new ServiceException(ServiceCode.ERROR_UPDATE, "修改失败，稍后重试");
        }
    }

    @Override
    public void addNew(AddNewBackUserDTO addNewBackUserDTO) {
        if (!isContainsId(addNewBackUserDTO)) {
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND, "新增失败，角色不存在");
        }
        if (backUserMapper.countByAccount(addNewBackUserDTO.getAccount()) > 0) {
            throw new ServiceException(ServiceCode.ERROR_CONFLICT, "新增用户失败，账户已存在");
        }
        String password;
        try {
            //密码加密
            password = AesCommon.encryptToStr(addNewBackUserDTO.getPassword(), aesKey, aesIv, AesCommon.AES_CBC_PKCS5);
            addNewBackUserDTO.setPassword(password);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        BackUser backUser = new BackUser();
        BeanUtils.copyProperties(addNewBackUserDTO, backUser);
        int result = backUserMapper.addNew(backUser);
        if (result != 1) {
            throw new ServiceException(ServiceCode.ERROR_INSERT, "新增用户失败，请稍后再试");
        }
    }

    /**
     * 判断参数中的Id[]是否在角色表中存在
     *
     * @param addNewBackUserDTO 新增后台用户DTO
     * @return 全存在 true 有不存在的false
     */

    public Boolean isContainsId(AddNewBackUserDTO addNewBackUserDTO) {
        return addNewBackUserDTO.getRoleIds().stream().allMatch(roleId ->
                backRoleMapper.getAllIds().stream().anyMatch(backRoleId ->
                        backRoleId.equals(roleId)));
    }

    /**
     * 验证后台用户是否存在
     *
     * @param backUserLoginDTO 后台用户登录DTO
     */
    private void validateBackUser(LoginInfoPO loginInfoPO, BackUserLoginDTO backUserLoginDTO) {
        //todo 密码加密

        if (!loginInfoPO.getAccount().equals(backUserLoginDTO.getAccount()) && !loginInfoPO.getPassword().equals(backUserLoginDTO.getPassword())) {
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND, "登录失败，用户不存在或账户密码错误");
        }
    }

    /**
     * 生成token参数map
     *
     * @return token
     */
    private String creteToken(Long id, List<Long> roleIds) {
        //token中要存储内容：用户id、角色id[]
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("userId", id);
        paramMap.put("roleIds", roleIds);
        paramMap.put("loginTime", System.currentTimeMillis());
        try {
            return AesCommon.encryptToStr(objectMapper.writeValueAsString(paramMap), aesKey, aesIv, AesCommon.AES_CBC_PKCS5);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 从redis中获取权限list
     */
    public List<LoginBackPermissionVO> getPermissionListByRedis(List<Long> roleIds) {
        Set<LoginBackPermissionVO> loginBackPermissionPOSet = new HashSet<>();
        for (Long roleId : roleIds) {
            try {
                List<LoginBackPermissionVO> loginBackPermissionVO = redissonCommon.getValue("role_permissions:" + objectMapper.writeValueAsString(roleId));
                // 获取role权限不为空
                if (loginBackPermissionVO != null && !loginBackPermissionVO.isEmpty()) {
                    loginBackPermissionPOSet.addAll(loginBackPermissionVO);
                }
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
        }
        return new ArrayList<>(loginBackPermissionPOSet);
    }
}
